package w83b.w83bUtilidades.w83bWebService;

import java.util.Iterator;

import javax.xml.rpc.soap.SOAPFaultException;
import javax.xml.soap.Detail;
import javax.xml.soap.DetailEntry;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;

import w83b.w83bUtilidadesComunes.W83bClsConstantes;
import w83b.w83bUtilidadesComunes.W83bClsTrazas;
import weblogic.webservice.core.soap.SOAPBodyElementImpl;
import weblogic.webservice.core.soap.SOAPFaultImpl;

/**
 * Clase que realiza una invocación al webService que se le pase como parámetro.
 */
public class W83bInvocacionWebService {
    
    // prefix - String giving the prefix of the namespace.
    // Siempre es "" para los webservices de integración 
    private static final String PREFIX = "";
    // uri - a String giving the URI of the namespace
    // Siempre es "http://www.openuri.org/" para los webservices de integración
    private static final String TARGET_NAMESPACE = "http://www.openuri.org/";

    private String url;
    private String method;
    private String[] paramNames;
    private String[] paramValues;
    private String prefix;
    private String targetNamespace;

    /**
     * Constructor del R02SWebService.
     * 
     * Define el prefix y el targetNamespace por defecto.
     * 
     * @param url
     * @param method
     * @param paramNames
     * @param paramValues
     */
    public W83bInvocacionWebService (String url, String method, String[] paramNames, String[] paramValues) {
        this.url = url;
        this.method = method;
        this.paramNames = paramNames;
        this.paramValues = paramValues;
        
        this.prefix = PREFIX;
        this.targetNamespace = TARGET_NAMESPACE;
    }    

    /**
     * Invoca al web service definido por this.
     * 
     * @return el resultado de la invocación soap
     * 
     * @throws Exception
     */
    public String invoke () throws Exception {
        String rtdo = "";
        try {
//        	 W83bClsTrazas.trazaError(null,"SOAPFaultException1: ",null);
            // creamos el mensaje SOAP.
            MessageFactory mfactory = MessageFactory.newInstance();
//            W83bClsTrazas.trazaError(null,"SOAPFaultException2: ",null);
            SOAPMessage message = mfactory.createMessage();
//            W83bClsTrazas.trazaError(null,"SOAPFaultException3: ",null);
            
            // conseguimos la parte SOAP del mensaje
            SOAPPart soapPart = message.getSOAPPart();
//            W83bClsTrazas.trazaError(null,"SOAPFaultException4: ",null);
            // conseguimos el envelope del soapPart
            SOAPEnvelope envelope = soapPart.getEnvelope();
//            W83bClsTrazas.trazaError(null,"SOAPFaultException5: ",null);
            // conseguimos el body del envelope
            SOAPBody body = envelope.getBody();
//            W83bClsTrazas.trazaError(null,"SOAPFaultException6: ",null);
            
            // conseguimos el tnsname del método al que se va a llamar
            Name name = envelope.createName(this.method, this.prefix, this.targetNamespace);
//            W83bClsTrazas.trazaError(null,"SOAPFaultException7: ",null);
            
            // creamos un new SOAPBodyElement objeto con el name especificado, y
            // lo añadimos al SOAPBody. Conseguimos la referencia al SOAPBodyElement
            // creado
//            W83bClsTrazas.trazaError(null,"SOAPFaultException8: ",null);
            SOAPBodyElement element = body.addBodyElement(name);

            // añadimos al body los elementos con los parámetros. Hay que conocer
            // el nombre del parámetro. (Aunque se podría conseguir con el wsdl)
            for (int i=0; i < this.paramNames.length && i < this.paramValues.length; i++) {
                SOAPElement param = element.addChildElement(envelope.createName( this.paramNames[i]) );
//                W83bClsTrazas.trazaError(null,"WS parameter: "+this.paramValues[i],null);
                param.addTextNode( this.paramValues[i] );
            }
//            W83bClsTrazas.trazaError(null,"SOAPFaultException9: ",null);
            
//            System.out.println("----------------------");
//            System.out.println("-- MESSAGE: ");
//            System.out.println("----------------------");
//            message.writeTo(System.out);
//            System.out.println("\n----------------------");

            // conseguimos una conexión SOAP.
            SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
//            W83bClsTrazas.trazaError(null,"SOAPFaultException10: ",null);
            SOAPConnection con = factory.createConnection();
//            W83bClsTrazas.trazaError(null,"SOAPFaultException11: ",null);

            // hacemos la llamada SOAP y recuperamos la respuesta
            SOAPMessage response = con.call(message, this.url);
//            W83bClsTrazas.trazaError(null,"SOAPFaultException12: ",null);
            
            // obtenemos el resultado en forma de String
            rtdo = getResultado(response);
//            W83bClsTrazas.trazaError(null,"SOAPFaultException12+1: ",null);
//            System.out.println("WebService: El resultado es: ["+rtdo+"]");

//            System.out.println("SOAP Message recibido:");
//            System.out.println("----------------------");
//            response.writeTo(System.out);
//            System.out.println("");
//            System.out.println("----------------------");
            
        }
        catch (SOAPFaultException e) {
            W83bClsTrazas.trazaError(null,"SOAPFaultException: "
                    + e.getFaultActor() + " - "
                    + e.getFaultCode() + " - "
                    + e.getFaultString() + " - "
                    + e.getMessage(),null);
            
            e.printStackTrace();
        }catch (SOAPException e) {
		W83bClsTrazas.trazaError(null,"SOAPException: "+ e.getMessage(),null);

            e.printStackTrace();
        }catch (Exception e) {
        	W83bClsTrazas.trazaError(null,"SOAPException: "+ e.getMessage(),null);
    	
        	e.printStackTrace();
        }
        
        return rtdo;
    }
    
    private static SOAPBodyElement getSOAPBodyElement (SOAPMessage response) throws SOAPException {
        SOAPBodyElement rtdo = null;

        Iterator iterator = response.getSOAPPart().getEnvelope().getBody().getChildElements();
        while (iterator.hasNext()) {
            Object oUndefined = iterator.next();

            if (oUndefined instanceof SOAPBodyElement) {
                rtdo = (SOAPBodyElement) oUndefined;
                break;
            }
        }
        return rtdo;
    }
    
    private static String getResultado (SOAPMessage response) throws SOAPException, Exception {
        String rtdo = "";
        
        W83bClsTrazas.traza(null,"response:\n"+response.toString()+"\n");

        SOAPBodyElement soapBodyElement = getSOAPBodyElement(response);
        W83bClsTrazas.traza(null,"soapBodyElement:\n"+soapBodyElement.toString()+"\n");
        
        if (soapBodyElement instanceof SOAPBodyElementImpl) {
            // todo ha ido bien... recogemos el resultado.

	        // String responseElementName = soapBodyElement.getElementName().toString();
	        // String resultElementName = responseElementName.replaceAll("Response$", "Result");
        	
//        	W83bClsTrazas.trazaError(null,"getResultado1: ",null);
        	
	        String resultElementName = "getNextDateResult";
	        
	        Iterator iterator = soapBodyElement.getChildElements();
	        while (iterator.hasNext()) {
	            SOAPElement element = (SOAPElement) iterator.next();
	            
	            String elementName = element.getElementName().toString();
//	            W83bClsTrazas.trazaError(null,"getResultado -> resultado "+elementName,null);
//	            W83bClsTrazas.trazaError(null,"getResultado -> resultado "+element.getValue(),null);
	            if (elementName.equals(resultElementName)) {
	                // el element es el elemento resultado.
	                rtdo = element.getValue();
	                break;
	            }
	        }
        }
        else if (soapBodyElement instanceof SOAPFaultImpl) {
            // ha ocurrido un error
        	W83bClsTrazas.trazaError(null,"getResultado2: ",null);
            
            SOAPFault fault = (SOAPFault) soapBodyElement;
            
            // tratamos el SOAPFault
            // nota: este método lanza una Exception
            tratarSOAPFault(fault);
        }
        else {
        	W83bClsTrazas.trazaError(null,"getResultado2: ",null);
            throw new Exception("El SOAPBodyElement no es una instancia de SOAPBodyElementImpl ni de SOAPFaulImpl");
        }
        
        return rtdo;
    }    
    
    /**
     * Tratamiento del SOAPFault.
     * 
     * @param fault
     * 
     * @throws Exception
     */
    private static void tratarSOAPFault(SOAPFault fault) throws Exception {
        StringBuffer mensajeError = new StringBuffer(W83bClsConstantes.CUARENTA);
        mensajeError.append("SOAPFault:\n");
        mensajeError.append("  faultCode: "+fault.getFaultCode()+"\n");
        mensajeError.append("  faultString: "+fault.getFaultString()+"\n");
        
        Detail detail = fault.getDetail();
        StringBuffer detailValue = new StringBuffer(W83bClsConstantes.CUARENTA);
        Iterator it = detail.getDetailEntries();
        while (it.hasNext()) {
            DetailEntry detailEntry = (DetailEntry) it.next();
            detailValue.append("  detailEntry: "+detailEntry.getValue() + "\n");
        }
        
        throw new Exception(mensajeError.toString());        
    }    

}
        